﻿using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Badger.Vhdl;
using Weazel.Badger.Vhdl.Types;
using Weazel.Badger.Vhdl.Statements;
using Weazel.Badger.Vhdl.Expressions;

namespace Weazel.Willows.InterfaceGeneration
{
	public class UserLogicEntity 
		: Weazel.Badger.RegisterEntity
	{
		/// <summary>
		/// Number of interrupts required (statically set to two for now)
		/// </summary>
		private int interruptCount = 2;

		/// <summary>
		/// Number of chip selects
		/// </summary>
		private int chipSelects;

		/// <summary>
		/// List of queues from hardware to software. Populated using
		/// the memory map in the constructor.
		/// </summary>
		private List<HardwareToSoftwareQueue> hardwareToSoftwareQueues =
			new List<HardwareToSoftwareQueue>();

		/// <summary>
		/// List of queues from software to hardware. Populated using 
		/// the memory map in the constructor.
		/// </summary>
		private List<SoftwareToHardwareQueue> softwareToHardwareQueues =
			new List<SoftwareToHardwareQueue>();

		/// <summary>
		/// Reference to the hardware-to-software status register.
		/// Set in the constructor.
		/// </summary>
		private StatusRegisterHardwareToSoftware hardwareToSoftwareStatusRegister;

		/// <summary>
		/// Reference to the software-to-hardware status register.
		/// Set in the constructor.
		/// </summary>
		private StatusRegisterSoftwareToHardware softwareToHardwareStatusRegister;

		/// <summary>
		/// Reference to the 'hardware' entity containing functionality placed
		/// in hardware. Set by constructor.
		/// </summary>
		private Weazel.Badger.ConversionEntity hardwareEntity;

		/// <summary>
		/// Ports of this entity. Specified in the IPIF specification
		/// </summary>
		private Port bus2IpClockPort;
		public Port Bus2IpClockPort
		{
			get { return bus2IpClockPort; }
		}
		private Port bus2IpResetPort;
		public Port Bus2IpResetPort
		{
			get { return bus2IpResetPort; }
		}
		private Port ip2BusInterruptEventPort;

		private Port bus2IpDataPort;
		public Port Bus2IpDataPort
		{
			get { return bus2IpDataPort; }
		}

		private Port bus2IpBePort;
		private Port bus2IpRdCePort;
		private Port bus2IpWrCePort;
		private Port ip2BusDataPort;
		private Port ip2BusAckPort;
		private Port ip2BusRetryPort;
		private Port ip2BusErrorPort;
		private Port ip2BusToutSupPort;

		private Weazel.Badger.Vhdl.Signal interruptSignal;
		private Weazel.Badger.Vhdl.Signal registerReadSelectSignal;
		private Weazel.Badger.Vhdl.Signal registerWriteSelectSignal;
		private Weazel.Badger.Vhdl.Signal ip2BusDataSignal;
		public Weazel.Badger.Vhdl.Signal Ip2BusDataSignal
		{
			get { return ip2BusDataSignal; }
		}
		private Weazel.Badger.Vhdl.Signal writeAcknowledgedSignal;
		private Weazel.Badger.Vhdl.Signal readAcknowledgedSignal;


		/// <summary>
		/// Reference to the read process
		/// </summary>
		private Process readProcess;
		public Process ReadProcess
		{
			get { return readProcess; }
		}

		/// <summary>
		/// Reference to the statement collection of the read process
		/// </summary>
		public StatementCollection ReadProcessStatementCollection
		{
			get { return ReadProcess.Statements; }
		}

		/// <summary>
		/// Reference to the case statement within the read process
		/// </summary>
		private CaseStatement readProcessCaseStatement;
		public CaseStatement ReadProcessCaseStatement
		{
			get { return readProcessCaseStatement; }
		}

		/// <summary>
		/// Reference to the write proces
		/// </summary>
		private Process writeProcess;
		public Process WriteProcess
		{
			get { return writeProcess; }			
		}

		/// <summary>
		/// Reference to the 'on reset' statement collection of the 
		/// write process
		/// </summary>
		private StatementCollection writeProcessOnResetStatementCollection;
		public StatementCollection WriteProcessOnResetStatementCollection
		{
			get { return writeProcessOnResetStatementCollection; }
		}

		/// <summary>
		/// Reference to the 'on clock' statement collection of the
		/// write process
		/// </summary>
		private StatementCollection writeProcessOnClockStatementCollection;
		public StatementCollection WriteProcessOnClockStatementCollection
		{
			get { return writeProcessOnClockStatementCollection; }
		}

		/// <summary>
		/// Reference to the case statement within the write process
		/// </summary>
		private CaseStatement writeProcessCaseStatement;
		public CaseStatement WriteProcessCaseStatement
		{
			get { return writeProcessCaseStatement; }
			set { writeProcessCaseStatement = value; }
		}

		/// <summary>
		/// Initializes the ports of the entity. 'chipSelects' must
		/// be set before calling this method
		/// </summary>
		private void initialize(List<MemoryMappedItem> items)
		{
			//
			// Ports
			//

			bus2IpClockPort =
				new Port(new StdLogic(), null, "Bus2IP_Clk", PortDirection.In, 0);
			AddPort(bus2IpClockPort);

			bus2IpResetPort =
				new Port(new StdLogic(), null, "Bus2IP_Reset", PortDirection.In, 1);
			AddPort(bus2IpResetPort);

			ip2BusInterruptEventPort =
				new Port(new StdLogicVector(interruptCount, true), null, "IP2Bus_IntrEvent", PortDirection.Out, 2);
			AddPort(ip2BusInterruptEventPort);

			bus2IpDataPort =
				new Port(new StdLogicVector(32, true), null, "Bus2IP_Data", PortDirection.In, 3);
			AddPort(bus2IpDataPort);

			bus2IpBePort =
				new Port(new StdLogicVector(4, true), null, "Bus2IP_BE", PortDirection.In, 4);
			AddPort(bus2IpBePort);

			bus2IpRdCePort =
				new Port(new StdLogicVector(chipSelects, true), null, "Bus2IP_RdCE", PortDirection.In, 5);
			AddPort(bus2IpRdCePort);

			bus2IpWrCePort =
				new Port(new StdLogicVector(chipSelects, true), null, "Bus2IP_WrCE", PortDirection.In, 6);
			AddPort(bus2IpWrCePort);

			ip2BusDataPort =
				new Port(new StdLogicVector(32, true), null, "IP2Bus_Data", PortDirection.Out, 7);
			AddPort(ip2BusDataPort);

			ip2BusAckPort =
				new Port(new StdLogic(), null, "IP2Bus_Ack", PortDirection.Out, 8);
			AddPort(ip2BusAckPort);

			ip2BusRetryPort =
				new Port(new StdLogic(), null, "IP2Bus_Retry", PortDirection.Out, 9);
			AddPort(ip2BusRetryPort);

			ip2BusErrorPort =
				new Port(new StdLogic(), null, "IP2Bus_Error", PortDirection.Out, 10);
			AddPort(ip2BusErrorPort);

			ip2BusToutSupPort =
				new Port(new StdLogic(), null, "IP2Bus_ToutSup", PortDirection.Out, 11);
			AddPort(ip2BusToutSupPort);

			//
			// Signals
			//

			registerReadSelectSignal = new Weazel.Badger.Vhdl.Signal(new StdLogicVector(chipSelects), null, "register_read_select");
			Signals.Add(registerReadSelectSignal);
			AddDeclarativeItem(registerReadSelectSignal);

			registerWriteSelectSignal = new Weazel.Badger.Vhdl.Signal(new StdLogicVector(chipSelects), null, "register_write_select");
			Signals.Add(registerWriteSelectSignal);
			AddDeclarativeItem(registerWriteSelectSignal);

			ip2BusDataSignal = new Weazel.Badger.Vhdl.Signal(new StdLogicVector(32, true), null, "ip_to_bus_data");
			Signals.Add(ip2BusDataSignal);
			AddDeclarativeItem(ip2BusDataSignal);

			readAcknowledgedSignal = new Weazel.Badger.Vhdl.Signal(new StdLogic(), null, "read_ack");
			Signals.Add(readAcknowledgedSignal);
			AddDeclarativeItem(readAcknowledgedSignal);

			writeAcknowledgedSignal = new Weazel.Badger.Vhdl.Signal(new StdLogic(), null, "write_ack");
			Signals.Add(writeAcknowledgedSignal);
			AddDeclarativeItem(writeAcknowledgedSignal);

			interruptSignal = new Signal(new StdLogicVector(interruptCount), null, "interrupt");
			Signals.Add(interruptSignal);
			AddDeclarativeItem(interruptSignal);

			// add signals from connections

			foreach (MemoryMappedItem item in items)
			{
				if (item is SoftwareToHardwareQueue)
				{
					SoftwareToHardwareQueue connection =
						item as SoftwareToHardwareQueue;

					// make the queue insert itself
					connection.InsertIntoUserLogicEntity(this);
				}
				else if (item is HardwareToSoftwareQueue)
				{
					HardwareToSoftwareQueue connection =
						item as HardwareToSoftwareQueue;

					// make the queue insert itself
					connection.InsertIntoUserLogicEntity(this);
				}
				else if (item is StatusRegisterHardwareToSoftware)
				{
					StatusRegisterHardwareToSoftware register =
						item as StatusRegisterHardwareToSoftware;


				}
				else if (item is StatusRegisterSoftwareToHardware)
				{
					StatusRegisterSoftwareToHardware register =
						item as StatusRegisterSoftwareToHardware;
				}
				else
				{
					throw new NotSupportedException();
				}
			}

		}


		private string relativeAddressToExpression(int chipSelects, int relativeAddress)
		{
			StringBuilder str = new StringBuilder();
			for (int i = 0; i < chipSelects; i++)
				str.Append('0');
			str.Replace('0', '1', relativeAddress, 1);
			str.Insert(0, "\"");
			str.Append("\"");

			return str.ToString();
		}

		private IfStatement createWriteProcessIfStatement(

			StatementCollection onResetStatements,
			StatementCollection onClockStatements
		)
		{
			AttributeExpression clocksEventExpr =
				new AttributeExpression(writeProcess.Statements, bus2IpClockPort.EventAttribute);

			BinaryExpression clockEqualsOneExpr =
				new BinaryExpression(writeProcess.Statements,
				Weazel.Badger.Vhdl.Operators.BinaryOperators.Equals,
				new SignalReferenceExpression(
					writeProcess.Statements,
					bus2IpClockPort
				),
				new Weazel.Badger.Vhdl.Expressions.ConstantExpression(
					writeProcess.Statements,
					"1",
					new StdLogic(),
					null
				),
				new Weazel.Badger.Vhdl.Types.Boolean(),
				null
			);

			IfStatement ifClockStatement = new IfStatement();
			ifClockStatement.Condition =
				new BinaryExpression(
					writeProcess.Statements,
					Weazel.Badger.Vhdl.Operators.BinaryOperators.And,
					clocksEventExpr,
					clockEqualsOneExpr,
					new Weazel.Badger.Vhdl.Types.Boolean(),
					null
				);

			IfStatement ifResetStatement = new IfStatement();
			ifResetStatement.Condition =
				new BinaryExpression(
					ifClockStatement.TrueStatements,
					Weazel.Badger.Vhdl.Operators.BinaryOperators.Equals,
					new SignalReferenceExpression(
						ifClockStatement.TrueStatements,
						bus2IpResetPort
					),
					new Weazel.Badger.Vhdl.Expressions.ConstantExpression(
						writeProcess.Statements,
						"1",
						new StdLogic(),
						null
					),
					new Weazel.Badger.Vhdl.Types.Boolean(),
					null
				);

			ifClockStatement.TrueStatements.Add(ifResetStatement);

			ifResetStatement.TrueStatements = onResetStatements;
			ifResetStatement.FalseStatements = onClockStatements;

			return ifClockStatement;
		}

		private void createBusWriteProcess(List<MemoryMappedItem> items)
		{
			writeProcess = new Process("bus_write", this);
			Processes.Add(writeProcess);

			writeProcess.AddSignalToSensivitityList(bus2IpClockPort);

			this.writeProcessOnClockStatementCollection = new StatementCollection();
			this.writeProcessOnResetStatementCollection = new StatementCollection();

			writeProcess.Statements.Add(
				createWriteProcessIfStatement(
					this.writeProcessOnResetStatementCollection,
					this.writeProcessOnClockStatementCollection
				)
			);

			this.writeProcessCaseStatement = new CaseStatement();

			// add case statement to 'on clock' 
			writeProcessOnClockStatementCollection.Add(writeProcessCaseStatement);

			// branch on value of write select signal
			this.writeProcessCaseStatement.Expression =
				new SignalReferenceExpression(
					writeProcessOnClockStatementCollection, 
					registerWriteSelectSignal
				);

			foreach (MemoryMappedItem item in items)
			{
				item.SetupWriteProcessCase(this);
			}

			this.writeProcessCaseStatement.OthersStatements.Add(new BlackBoxStatement("null;"));
		}

		private void createBusReadProcess(List<MemoryMappedItem> items)
		{
			readProcess = new Process("bus_read", this);
			Processes.Add(readProcess);

			readProcess.AddSignalToSensivitityList(registerReadSelectSignal);
			readProcess.AddSignalToSensivitityList(bus2IpClockPort);

			this.readProcessCaseStatement = new CaseStatement();

			// branch on value of read select signal
			this.readProcessCaseStatement.Expression =
				new SignalReferenceExpression(readProcess.Statements, registerReadSelectSignal);

			foreach (MemoryMappedItem item in items)
			{
				// each item will insert a case choice in the
				// statement collection..
				item.SetupReadProcessCase(this);
			}

			// finally handle the others case 
			SignalAssignmentStatement assignAllZeros =
				new SignalAssignmentStatement(
					ip2BusDataSignal,
					new AggregateExpression(
						this.readProcessCaseStatement.OthersStatements,
						AggregateAssociations.SetAll,
						ip2BusDataSignal,
						"'0'"
					)
				);

			this.readProcessCaseStatement.OthersStatements.Add(assignAllZeros);
			readProcess.Statements.Add(this.readProcessCaseStatement);
		}

		/// <summary>
		/// Setup the interrupt signal. 
		/// </summary>
		private void createInterruptWiring()
		{
			//
			// interrupt signal to interrupt port
			// eg. IP2Bus_IntrEvent <= interrupt;
			//
			SignalAssignmentStatement assignInterruptPort =
				new SignalAssignmentStatement(
					ip2BusInterruptEventPort,
					new SignalReferenceExpression(Statements, interruptSignal)
				);

			Statements.Add(assignInterruptPort);

			// setup interrupt sources (hw to sw queues)
			// interrupt(1) <= q1_no_longer_empty or q2_no_longer_empty ...

			if(hardwareToSoftwareQueues.Count > 0)
			{
				// first 
				Expression expr = 
					new SignalReferenceExpression(
						Statements,
						hardwareToSoftwareQueues[0].NoLongerEmptySignal
					);

				// all others 
				for (int i = 1; i < hardwareToSoftwareQueues.Count; i++)
				{
					expr =
						new BinaryExpression(
							Statements,
							Weazel.Badger.Vhdl.Operators.BinaryOperators.Or,
							expr,
							new SignalReferenceExpression(
								Statements,
								hardwareToSoftwareQueues[i].NoLongerEmptySignal
							),
							new StdLogic(),
							null
						);
				}

				// set interrupt(0) <= expr
				SignalAssignmentStatement assignInterrupt1 =
					new SignalAssignmentStatement(
						interruptSignal,
						expr,
						0,
						0,
						false
					);

				Statements.Add(assignInterrupt1);
			}
		}

		private void createEntityLevelWiring()
		{
			createInterruptWiring();

			Weazel.Badger.Vhdl.Expressions.ConstantExpression zero =
				new Weazel.Badger.Vhdl.Expressions.ConstantExpression(
					null,
					"0",
					new StdLogic(),
					null
				);

			// register read select signal

			SignalAssignmentStatement assignRegisterReadSelectSignal =
				new SignalAssignmentStatement(
					registerReadSelectSignal,
					new ArrayIndexExpression(
						Statements,
						new SignalReferenceExpression(Statements, bus2IpRdCePort),
						new Weazel.Badger.Vhdl.Expressions.ConstantExpression(0),
						new Weazel.Badger.Vhdl.Expressions.ConstantExpression(chipSelects - 1),
						true,
						null,
						null
					)
				);

			Statements.Add(assignRegisterReadSelectSignal);

			// register write select signal

			SignalAssignmentStatement assignRegisterWriteSelectSignal =
				new SignalAssignmentStatement(
					registerWriteSelectSignal,
					new ArrayIndexExpression(
						Statements,
						new SignalReferenceExpression(Statements, bus2IpWrCePort),
						new Weazel.Badger.Vhdl.Expressions.ConstantExpression(0),
						new Weazel.Badger.Vhdl.Expressions.ConstantExpression(chipSelects - 1),
						true,
						null,
						null
					)
				);

			Statements.Add(assignRegisterWriteSelectSignal);

			SignalAssignmentStatement assignIp2BusAck =
				new SignalAssignmentStatement(
					ip2BusAckPort,
					new BinaryExpression(
						null,
						Weazel.Badger.Vhdl.Operators.BinaryOperators.Or,
						new SignalReferenceExpression(null, readAcknowledgedSignal),
						new SignalReferenceExpression(null, writeAcknowledgedSignal),
						new StdLogic(),
						null
					)
				);

			Statements.Add(assignIp2BusAck);

			SignalAssignmentStatement assignIp2BusError =
				new SignalAssignmentStatement(
					ip2BusErrorPort,
					zero
				);

			Statements.Add(assignIp2BusError);

			SignalAssignmentStatement assignIp2BusRetry =
				new SignalAssignmentStatement(
					ip2BusRetryPort,
					zero
				);

			Statements.Add(assignIp2BusRetry);

			SignalAssignmentStatement assignIp2BusToutSup =
				new SignalAssignmentStatement(
					ip2BusToutSupPort,
					zero
				);

			Statements.Add(assignIp2BusToutSup);

			SignalAssignmentStatement assignIp2BusData =
				new SignalAssignmentStatement(
					ip2BusDataPort,
					new SignalReferenceExpression(null, ip2BusDataSignal)
				);

			Statements.Add(assignIp2BusData);

			// write ack
			Expression writeSelectOrExpression =
				new ArrayIndexExpression(
					Statements,
					new SignalReferenceExpression(null, bus2IpWrCePort),
					new Weazel.Badger.Vhdl.Expressions.ConstantExpression(
						null,
						"0",
						new Integer(1),
						null
					),
					null
				);

			for (int i = 1; i < chipSelects; i++)
			{
				ArrayIndexExpression e =
					new ArrayIndexExpression(
						Statements,
						new SignalReferenceExpression(null, bus2IpWrCePort),
						new Weazel.Badger.Vhdl.Expressions.ConstantExpression(
							null,
							i.ToString(),
							new Integer(1),
							null
						),
						null
					);

				writeSelectOrExpression =
					new BinaryExpression(
						Statements,
						Weazel.Badger.Vhdl.Operators.BinaryOperators.Or,
						writeSelectOrExpression,
						e,
						new StdLogic(),
						null
					);
			}

			SignalAssignmentStatement assignWriteAcknowledged =
				new SignalAssignmentStatement(
					writeAcknowledgedSignal,
					writeSelectOrExpression
				);

			Statements.Add(assignWriteAcknowledged);

			// read ack
			Expression readSelectOrExpression =
				new ArrayIndexExpression(
					Statements,
					new SignalReferenceExpression(null, bus2IpRdCePort),
					new Weazel.Badger.Vhdl.Expressions.ConstantExpression(
						null,
						"0",
						new Integer(1),
						null
					),
					null
				);

			for (int i = 1; i < chipSelects; i++)
			{
				ArrayIndexExpression e =
					new ArrayIndexExpression(
						Statements,
						new SignalReferenceExpression(null, bus2IpRdCePort),
						new Weazel.Badger.Vhdl.Expressions.ConstantExpression(
							null,
							i.ToString(),
							new Integer(1),
							null
						),
						null
					);

				readSelectOrExpression =
					new BinaryExpression(
						Statements,
						Weazel.Badger.Vhdl.Operators.BinaryOperators.Or,
						readSelectOrExpression,
						e,
						new StdLogic(),
						null
					);
			}

			SignalAssignmentStatement assignReadAcknowledged =
				new SignalAssignmentStatement(
					readAcknowledgedSignal,
					readSelectOrExpression
				);

			Statements.Add(assignReadAcknowledged);
		}

		private void buildHardwareEntityPortMap()
		{
			System.Diagnostics.Trace.Assert(hardwareEntity != null);

			PortMap map = new PortMap("hardware_port_map", hardwareEntity.Name);

			Dictionary<string, string> tempPortNameMap = new Dictionary<string, string>();

			foreach (Port port in hardwareEntity.Ports)
				tempPortNameMap.Add(port.Name, null);			

			foreach(SoftwareToHardwareQueue queue in softwareToHardwareQueues)
			{
				if (!tempPortNameMap.ContainsKey(queue.HardwareCanReadPortName))
					{
						throw new Exception(
							string.Format("Cannot find can read port in hardware port '{0}' in hardware port list",
							queue.HardwareCanReadPortName));
					}

					tempPortNameMap[queue.HardwareCanReadPortName] =
						queue.ReadingEndCanReadSignal.Name;

					if (!tempPortNameMap.ContainsKey(queue.HardwareDataOutPortName))
						throw new Exception(
							string.Format(
							"Cannot find data out port in hardware port '{0}' in hardware port list",
							queue.HardwareDataOutPortName)
						);

					tempPortNameMap[queue.HardwareDataOutPortName] =
						queue.ReadingEndDataSignal.Name;

					if (!tempPortNameMap.ContainsKey(queue.HardwareDoReadPortName))
						throw new Exception(
							string.Format("Cannot find do read port in hardware port '{0}' in hardware port list",
							queue.HardwareDoReadPortName)
						);

					tempPortNameMap[queue.HardwareDoReadPortName] =
						queue.ReadingEndDoReadSignal.Name;
			}

			foreach(HardwareToSoftwareQueue queue in hardwareToSoftwareQueues)
			{
				// check that the 'can_write' port is present on the hardware entity
				if (!tempPortNameMap.ContainsKey(queue.HardwareCanWritePortName))
				{
					// Unexpected
					string message =
						string.Format("Cannot find can write port '{0}' in hardware port list", 
						queue.HardwareCanWritePortName);

					throw new Exception(message);
				}

				tempPortNameMap[queue.HardwareCanWritePortName] =
					queue.WritingEndCanWriteSignal.Name;	


				// check that the 'data_in' port is present on the hardware entity
				if (!tempPortNameMap.ContainsKey(queue.HardwareDataInPortName))
				{
					string message =
						string.Format("Cannot find data in port in hardware port '{0}' in hardware port list", 
						queue.HardwareCanWritePortName);

					throw new Exception(message);
				}

				tempPortNameMap[queue.HardwareDataInPortName] = 
					queue.WritingEndDataSignal.Name;

				// check that the 'do_write' port is present on the hardware entity
				if (!tempPortNameMap.ContainsKey(queue.HardwareDoWritePortName))
				{
					string message =
						string.Format("Cannot find do write port in hardware port '{0}' in hardware port list",
						queue.HardwareDoWritePortName);

					throw new Exception(message);
				}

				tempPortNameMap[queue.HardwareDoWritePortName] = 
					queue.WritingEndDoWriteSignal.Name;
			}

			foreach (string key in tempPortNameMap.Keys)
			{
				if (key == "clock")
					map.Add("clock", "Bus2IP_Clk");
				else if (key == "reset")
					map.Add("reset", "Bus2IP_Reset");
				else
				{
					if (tempPortNameMap[key] == null)
						throw new NullReferenceException();

					map.Add(key, tempPortNameMap[key]);
				}
			}

			AddPortMap(map);
		}

		public UserLogicEntity(MemoryMap memoryMap, Weazel.Badger.ConversionEntity hardwareEntity)
			: base("user_logic")
		{
			// set the number of chip selects needed 
			chipSelects = memoryMap.AddressesNeeded;

			// create signals and ports (must be done before adding queues)
			initialize(memoryMap.Items);

			//
			// Populate lists of queues and the two status register references
			//
			foreach (MemoryMappedItem item in memoryMap.Items)
			{
				if (item is HardwareToSoftwareQueue)
					hardwareToSoftwareQueues.Add(item as HardwareToSoftwareQueue);
				else if (item is SoftwareToHardwareQueue)
					softwareToHardwareQueues.Add(item as SoftwareToHardwareQueue);
				else if (item is StatusRegisterHardwareToSoftware)
					hardwareToSoftwareStatusRegister = item as StatusRegisterHardwareToSoftware;
				else if (item is StatusRegisterSoftwareToHardware)
					softwareToHardwareStatusRegister = item as StatusRegisterSoftwareToHardware;
				else
					throw new NotSupportedException();
			}

			System.Diagnostics.Trace.Assert(hardwareToSoftwareStatusRegister != null);
			System.Diagnostics.Trace.Assert(softwareToHardwareStatusRegister != null);

			//
			// Initialize
			// 
			foreach (HardwareToSoftwareQueue queue in hardwareToSoftwareQueues)
			{
				// insert queue (component, portmaps, wireing..)
				queue.InsertQueue(this);

				// insert signals 
				queue.InsertIntoUserLogicEntity(this);
			}

			foreach (SoftwareToHardwareQueue queue in softwareToHardwareQueues)
			{
				// insert queue (component, portmaps, wireing..)
				queue.InsertQueue(this);

				// insert signals
				queue.InsertIntoUserLogicEntity(this);
			}

			// Needed to match enclosing ipif implementation file (weazel.vhd)
			this.Generic =
				"generic( C_DWIDTH	: integer	:= 32; C_NUM_CE	: integer	:= 3; C_IP_INTR_NUM	: integer	:= 2);";

			// setup the 'hardware' entity
			this.hardwareEntity = hardwareEntity;
			AddDeclarativeItem(hardwareEntity.GetDeclaration());
			buildHardwareEntityPortMap();

			createBusWriteProcess(memoryMap.Items);
			createBusReadProcess(memoryMap.Items);
			createEntityLevelWiring();
		}
	}
}
